home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / WIN32SERVICEUTIL.PY < prev    next >
Encoding:
Python Source  |  1999-02-04  |  21.1 KB  |  592 lines

  1. # Utility functions for Python programs which run as services...
  2. #
  3. # Note that most utility functios here will raise win32api.error's when
  4. # things go wrong - eg, not enough permissions to hit the registry etc.
  5.  
  6. import win32service, win32api, win32con, winerror
  7. import sys, string, pywintypes, os
  8.  
  9. error = "Python Service Utility Error"
  10.  
  11. def LocatePythonServiceExe(exeName = None):
  12.     # Try and find the specified EXE somewhere.  If specifically registered,
  13.     # use it.  Otherwise look down sys.path, and the global PATH environment.
  14.     if exeName is None: exeName = "PythonService.exe"
  15.     # See if it exists as specified
  16.     if os.path.isfile(exeName): return win32api.GetFullPathName(exeName)
  17.     baseName = os.path.splitext(os.path.basename(exeName))[0]
  18.     try:
  19.         return win32api.RegQueryValue(win32con.HKEY_LOCAL_MACHINE, "Software\\Python\\%s\\%s" % (baseName, sys.winver))
  20.     except win32api.error:
  21.         # OK - not there - lets go a-searchin'
  22.         for path in sys.path:
  23.             look = os.path.join(path, exeName)
  24.             if os.path.isfile(look):
  25.                 return win32api.GetFullPathName(look)
  26.         # Try the global Path.
  27.         try:
  28.             return win32api.SearchPath(None, exeName)
  29.         except win32api.error:
  30.             msg = "%s is not correctly registered\nPlease locate and run %s.exe, and it will self-register\nThen run this service registration process again." % (exeName, exeName)
  31.             raise error, msg
  32.  
  33. def LocateSpecificServiceExe(serviceName):
  34.     # Given the name of a specific service, return the .EXE name _it_ uses
  35.     # (which may or may not be the Python Service EXE
  36.     hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS)
  37.     try:
  38.         return win32api.RegQueryValueEx(hkey, "ImagePath")[0]
  39.     finally:
  40.         hkey.Close()
  41.     
  42. def InstallPerfmonForService(serviceName, iniName, dllName = None):
  43.     # If no DLL name, look it up in the INI file name
  44.     if dllName is None:
  45.         dllName = win32api.GetProfileVal("Python", "dll", "", iniName)
  46.     if dllName is None:
  47.         raise ValueError, "The name of the performance DLL must be available"
  48.     dllName = win32api.GetFullPathName(dllName)
  49.     # Now setup all the required "Performance" entries.
  50.     hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS)
  51.     try:
  52.         subKey = win32api.RegCreateKey(hkey, "Performance")
  53.         try:
  54.             win32api.RegSetValueEx(subKey, "Library", 0, win32con.REG_SZ, dllName)
  55.             win32api.RegSetValueEx(subKey, "Open", 0, win32con.REG_SZ, "OpenPerformanceData")
  56.             win32api.RegSetValueEx(subKey, "Close", 0, win32con.REG_SZ, "ClosePerformanceData")
  57.             win32api.RegSetValueEx(subKey, "Collect", 0, win32con.REG_SZ, "CollectPerformanceData")
  58.         finally:
  59.             win32api.RegCloseKey(subKey)
  60.     finally:
  61.         win32api.RegCloseKey(hkey)
  62.     # Now do the "Lodctr" thang...
  63.  
  64.     try:
  65.         import perfmon, os
  66.         path, fname = os.path.split(iniName)
  67.         oldPath = os.getcwd()
  68.         if path:
  69.             os.chdir(path)
  70.         try:
  71.             perfmon.LoadPerfCounterTextStrings("python.exe " + fname)
  72.         finally:
  73.             os.chdir(oldPath)
  74.     except win32api.error, details:
  75.         print "The service was installed OK, but the performance monitor"
  76.         print "data could not be loaded.", details
  77.  
  78. def InstallService(pythonClassString, serviceName, displayName, startType = None, errorControl = None, bRunInteractive = 0, serviceDeps = None, userName = None, password = None, exeName = None, perfMonIni = None, perfMonDll = None):
  79.     # Handle the default arguments.
  80.     if startType is None:
  81.         startType = win32service.SERVICE_DEMAND_START
  82.         if bRunInteractive:
  83.             startType = startType | win32service.SERVICE_INTERACTIVE_PROCESS
  84.     if errorControl is None:
  85.         errorControl = win32service.SERVICE_ERROR_NORMAL
  86.  
  87.     exeName = '"%s"' % LocatePythonServiceExe(exeName) # None here means use default PythonService.exe
  88.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  89.     try:
  90.         hs = win32service.CreateService(hscm,
  91.                     serviceName,
  92.                     displayName,
  93.                     win32service.SERVICE_ALL_ACCESS,         # desired access
  94.                     win32service.SERVICE_WIN32_OWN_PROCESS,  # service type
  95.                     startType,
  96.                     errorControl,       # error control type
  97.                     exeName,
  98.                     None,
  99.                     0,
  100.                     serviceDeps,
  101.                     userName,
  102.                     password)
  103.         win32service.CloseServiceHandle(hs)
  104.     finally:
  105.         win32service.CloseServiceHandle(hscm)
  106.     InstallPythonClassString(pythonClassString, serviceName)
  107.     # If I have performance monitor info to install, do that.
  108.     if perfMonIni is not None:
  109.         InstallPerfmonForService(serviceName, perfMonIni, perfMonDll)
  110.  
  111. def ChangeServiceConfig(pythonClassString, serviceName, startType = None, errorControl = None, serviceDeps = None, userName = None, password = None, exeName = None, displayName = None, perfMonIni = None, perfMonDll = None):
  112.     # Before doing anything, remove any perfmon counters.
  113.     try:
  114.         import perfmon
  115.         perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName)
  116.     except (ImportError, win32api.error):
  117.         pass
  118.  
  119.     # The EXE location may have changed
  120.     exeName = '"%s"' % LocatePythonServiceExe(exeName)
  121.     
  122.     # Handle the default arguments.
  123.     if startType is None: startType = win32service.SERVICE_NO_CHANGE
  124.     if errorControl is None: errorControl = win32service.SERVICE_NO_CHANGE
  125.  
  126.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  127.     try:
  128.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  129.         try:
  130.  
  131.             win32service.ChangeServiceConfig(hs,
  132.                     win32service.SERVICE_NO_CHANGE,  # service type
  133.                     startType,
  134.                     errorControl,       # error control type
  135.                     exeName,
  136.                     None,
  137.                     0,
  138.                     serviceDeps,
  139.                     userName,
  140.                     password,
  141.                 displayName)
  142.         finally:
  143.             win32service.CloseServiceHandle(hs)
  144.     finally:
  145.         win32service.CloseServiceHandle(hscm)
  146.     InstallPythonClassString(pythonClassString, serviceName)
  147.     # If I have performance monitor info to install, do that.
  148.     if perfMonIni is not None:
  149.         InstallPerfmonForService(serviceName, perfMonIni, perfMonDll)
  150.  
  151. def InstallPythonClassString(pythonClassString, serviceName):
  152.     # Now setup our Python specific entries.
  153.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\PythonClass" % serviceName)
  154.     try:
  155.         win32api.RegSetValue(key, None, win32con.REG_SZ, pythonClassString);
  156.     finally:
  157.         win32api.RegCloseKey(key)
  158.  
  159. # Utility functions for Services, to allow persistant properties.
  160. def SetServiceCustomOption(serviceName, option, value):
  161.     try:
  162.         serviceName = serviceName._svc_name_
  163.     except AttributeError:
  164.         pass
  165.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName)
  166.     try:
  167.         if type(value)==type(0):
  168.             win32api.RegSetValueEx(key, option, 0, win32con.REG_DWORD, value);
  169.         else:
  170.             win32api.RegSetValueEx(key, option, 0, win32con.REG_SZ, value);
  171.     finally:
  172.         win32api.RegCloseKey(key)
  173.  
  174. def GetServiceCustomOption(serviceName, option, defaultValue = None):
  175.     # First param may also be a service class/instance.
  176.     # This allows services to pass "self"
  177.     try:
  178.         serviceName = serviceName._svc_name_
  179.     except AttributeError:
  180.         pass
  181.     key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName)
  182.     try:
  183.         try:
  184.             return win32api.RegQueryValueEx(key, option)[0]
  185.         except win32api.error:    # No value.
  186.             return defaultValue
  187.     finally:
  188.         win32api.RegCloseKey(key)
  189.  
  190.  
  191. def RemoveService(serviceName):
  192.     try:
  193.         import perfmon
  194.         perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName)
  195.     except (ImportError, win32api.error):
  196.         pass
  197.  
  198.     hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
  199.     try:
  200.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  201.         win32service.DeleteService(hs)
  202.     finally:
  203.         win32service.CloseServiceHandle(hscm)
  204.  
  205. def ControlService(serviceName, code, machine = None):
  206.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  207.     try:
  208.  
  209.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  210.         try:
  211.             status = win32service.ControlService(hs, code)
  212.         finally:
  213.             win32service.CloseServiceHandle(hs)
  214.     finally:
  215.         win32service.CloseServiceHandle(hscm)
  216.     return status
  217.  
  218. def __FindSvcDeps(findName):
  219.     if type(findName) is pywintypes.UnicodeType: findName = str(findName)
  220.     dict = {}
  221.     k = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services")
  222.     num = 0
  223.     while 1:
  224.         try:
  225.             svc = win32api.RegEnumKey(k, num)
  226.         except win32api.error:
  227.             break
  228.         num = num + 1
  229.         sk = win32api.RegOpenKey(k, svc)
  230.         try:
  231.             deps, typ = win32api.RegQueryValueEx(sk, "DependOnService")
  232.         except win32api.error:
  233.             deps = ()
  234.         for dep in deps:
  235.             dep = string.lower(dep)
  236.             dep_on = dict.get(dep, [])
  237.             dep_on.append(svc)
  238.             dict[dep]=dep_on
  239.             
  240.     return __ResolveDeps(findName, dict)
  241.  
  242.             
  243. def __ResolveDeps(findName, dict):
  244.     items = dict.get(string.lower(findName), [])
  245.     retList = []
  246.     for svc in items:
  247.         retList.insert(0, svc)
  248.         retList = __ResolveDeps(svc, dict) + retList
  249.     return retList
  250.     
  251. def __StopServiceWithTimeout(hs, waitSecs = 30):
  252.     try:
  253.         status = win32service.ControlService(hs, win32service.SERVICE_CONTROL_STOP)
  254.     except pywintypes.error, (hr, name, msg):
  255.         if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE:
  256.             raise win32service.error, (hr, name, msg)
  257.     for i in range(waitSecs):
  258.         status = win32service.QueryServiceStatus(hs)
  259.         if status[1] == win32service.SERVICE_STOPPED:
  260.             break
  261.         win32api.Sleep(1000)
  262.     else:
  263.         raise pywintypes.error, (winerror.ERROR_SERVICE_REQUEST_TIMEOUT, "ControlService", win32api.FormatMessage(winerror.ERROR_SERVICE_REQUEST_TIMEOUT)[:-2])
  264.  
  265.  
  266. def StopServiceWithDeps(serviceName, machine = None, waitSecs = 30):
  267.     # Stop a service recursively looking for dependant services
  268.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  269.     try:
  270.         deps = __FindSvcDeps(serviceName)
  271.         for dep in deps:
  272.             hs = win32service.OpenService(hscm, dep, win32service.SERVICE_ALL_ACCESS)
  273.             try:
  274.                 __StopServiceWithTimeout(hs, waitSecs)
  275.             finally:
  276.                 win32service.CloseServiceHandle(hs)
  277.         # Now my service!
  278.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  279.         try:
  280.             __StopServiceWithTimeout(hs, waitSecs)
  281.         finally:
  282.             win32service.CloseServiceHandle(hs)
  283.         
  284.     finally:
  285.         win32service.CloseServiceHandle(hscm)
  286.  
  287.  
  288. def StopService(serviceName, machine = None):
  289.     return ControlService(serviceName, win32service.SERVICE_CONTROL_STOP, machine)
  290.  
  291. def StartService(serviceName, args = None, machine = None):
  292.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS)
  293.     try:
  294.  
  295.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS)
  296.         try:
  297.             win32service.StartService(hs, args)
  298.         finally:
  299.             win32service.CloseServiceHandle(hs)
  300.     finally:
  301.         win32service.CloseServiceHandle(hscm)
  302.  
  303. def RestartService(serviceName, args = None, waitSeconds = 30, machine = None):
  304.     "Stop the service, and then start it again (with some tolerance for allowing it to stop.)"
  305.     try:
  306.         StopService(serviceName, machine)
  307.     except pywintypes.error, (hr, name, msg):
  308.         # Allow only "service not running" error
  309.         if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE:
  310.             raise win32service.error, (hr, name, msg)
  311.     # Give it a few goes, as the service may take time to stop
  312.     for i in range(waitSeconds):
  313.         try:
  314.             StartService(serviceName, args, machine)
  315.             break
  316.         except pywintypes.error, (hr, name, msg):
  317.             if hr!=winerror.ERROR_SERVICE_ALREADY_RUNNING:
  318.                 raise
  319.             win32api.Sleep(1000)
  320.     else:
  321.         print "Gave up waiting for the old service to stop!"
  322.         
  323.  
  324. def GetServiceClassString(cls, argv = None):
  325.         if argv is None:
  326.             argv = sys.argv
  327.         import pickle, os
  328.         modName = pickle.whichmodule(cls, cls.__name__)
  329.         if modName == '__main__':
  330.             try:
  331.                 fname = win32api.GetFullPathName(argv[0])
  332.                 path = os.path.split(fname)[0]
  333.                 # Eaaaahhhh - sometimes this will be a short filename, which causes 
  334.                 # problems with 1.5.1 and the silly filename case rule.
  335.                 # Get the long name
  336.                 fname = os.path.join(path, win32api.FindFiles(fname)[0][8])
  337.             except win32api.error:
  338.                 raise error, "Could not resolve the path name '%s' to a full path" % (argv[0])
  339.             modName = os.path.splitext(fname)[0]
  340.         return modName + "." + cls.__name__
  341.  
  342. def QueryServiceStatus(serviceName, machine=None):
  343.     hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_CONNECT)
  344.     try:
  345.  
  346.         hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_QUERY_STATUS)
  347.         try:
  348.             status = win32service.QueryServiceStatus(hs)
  349.         finally:
  350.             win32service.CloseServiceHandle(hs)
  351.     finally:
  352.         win32service.CloseServiceHandle(hscm)
  353.     return status
  354.  
  355. def usage():
  356.     try:
  357.         fname = os.path.split(sys.argv[0])[1]
  358.     except:
  359.         fname = sys.argv[0]
  360.     print "Usage: '%s [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'" % fname
  361.     print "Options for 'install' and 'update' commands only:"
  362.     print " --username domain\username : The Username the service is to run under"
  363.     print " --password password : The password for the username"
  364.     print " --startup [manual|auto|disabled] : How the service starts, default = manual"
  365.     sys.exit(1)
  366.  
  367. def HandleCommandLine(cls, serviceClassString = None, argv = None, customInstallOptions = "", customOptionHandler = None):
  368.     """Utility function allowing services to process the command line.
  369.     
  370.     Allows standard commands such as 'start', 'stop', 'debug', 'install' etc.
  371.     
  372.     Install supports 'standard' command line options prefixed with '--', such as
  373.     --username, --password, etc.  In addition,
  374.     the function allows custom command line options to be handled by the calling function.
  375.     """
  376.     err = 0
  377.     
  378.     if argv is None: argv = sys.argv
  379.  
  380.     if len(argv)<=1:
  381.         usage()
  382.  
  383.     serviceName = cls._svc_name_
  384.     serviceDisplayName = cls._svc_display_name_
  385.     if serviceClassString is None:
  386.         serviceClassString = GetServiceClassString(cls)
  387.  
  388.     # First we process all arguments which require access to the
  389.     # arg list directly
  390.     if argv[1]=="start":
  391.         print "Starting service %s" % (serviceName)
  392.         try:        
  393.             StartService(serviceName, argv[2:])
  394.         except win32service.error, (hr, fn, msg):
  395.             print "Error starting service: %s" % msg
  396.  
  397.     elif argv[1]=="restart":
  398.         print "Restarting service %s" % (serviceName)
  399.         RestartService(serviceName, argv[2:])
  400.     
  401.     elif argv[1]=="debug":
  402.         svcArgs = string.join(sys.argv[2:])
  403.         exeName = LocateSpecificServiceExe(serviceName)
  404.         try:
  405.             os.system("%s -debug %s %s" % (exeName, serviceName, svcArgs))
  406.         # ^C is used to kill the debug service.  Sometimes Python also gets
  407.         # interrupted - ignore it...
  408.         except KeyboardInterrupt:
  409.             pass
  410.     else:
  411.         # Pull apart the command line
  412.         import getopt
  413.         try:
  414.             opts, args = getopt.getopt(argv[1:], customInstallOptions,["password=","username=","startup=","perfmonini=", "perfmondll="])
  415.         except getopt.error, details:
  416.             print details
  417.             usage()
  418.         userName = None
  419.         password = None
  420.         perfMonIni = perfMonDll = None
  421.         startup = None
  422.         for opt, val in opts:
  423.             if opt=='--username':
  424.                 userName = val
  425.             elif opt=='--password':
  426.                 password = val
  427.             elif opt=='--perfmonini':
  428.                 perfMonIni = val
  429.             elif opt=='--perfmondll':
  430.                 perfMonDll = val
  431.             elif opt=='--startup':
  432.                 map = {"manual": win32service.SERVICE_DEMAND_START, "auto" : win32service.SERVICE_AUTO_START, "disabled": win32service.SERVICE_DISABLED}
  433.                 try:
  434.                     startup = map[string.lower(val)]
  435.                 except KeyError:
  436.                     print "'%s' is not a valid startup option" % val
  437.         if len(args)<>1:
  438.             usage()
  439.         arg=args[0]
  440.         knownArg = 0
  441.         if arg=="install":
  442.             knownArg = 1
  443.             try:
  444.                 serviceDeps = cls._svc_deps_
  445.             except AttributeError:
  446.                 serviceDeps = None
  447.             try:
  448.                 exeName = cls._exe_name_
  449.             except AttributeError:
  450.                 exeName = None # Default to PythonService.exe
  451.             print "Installing service %s to Python class %s" % (serviceName,serviceClassString)
  452.             # Note that we install the service before calling the custom option
  453.             # handler, so if the custom handler fails, we have an installed service (from NT's POV)
  454.             # but is unlikely to work, as the Python code controlling it failed.  Therefore
  455.             # we remove the service if the first bit works, but the second doesnt!
  456.             try:
  457.                 InstallService(serviceClassString, serviceName, serviceDisplayName, serviceDeps = serviceDeps, startType=startup, userName=userName,password=password, exeName=exeName, perfMonIni=perfMonIni,perfMonDll=perfMonDll)
  458.                 if customOptionHandler:
  459.                     apply( customOptionHandler, (opts,) )
  460.                 print "Service installed"
  461.             except win32service.error, (hr, fn, msg):
  462.                 if hr==winerror.ERROR_SERVICE_EXISTS:
  463.                     arg = "update" # Fall through to the "update" param!
  464.                 else:
  465.                     print "Error installing service: %s" % msg
  466.                     err = hr
  467.             except ValueError, msg: # Can be raised by custom option handler.
  468.                 print "Error installing service: %s" % str(msg)
  469.                 # As we failed here, remove the service, so the next installation
  470.                 # attempt works.
  471.                 try:
  472.                     RemoveService(serviceName)
  473.                 except win32api.error:
  474.                     print "Warning - could not remove the partially installed service."
  475.                 err = -1
  476.  
  477.         if arg == "update":
  478.             knownArg = 1
  479.             try:
  480.                 serviceDeps = cls._svc_deps_
  481.             except AttributeError:
  482.                 serviceDeps = None
  483.             try:
  484.                 exeName = cls._exe_name_
  485.             except AttributeError:
  486.                 exeName = None # Default to PythonService.exe
  487.             print "Changing service configuration"
  488.             try:
  489.                 ChangeServiceConfig(serviceClassString, serviceName, serviceDeps = serviceDeps, startType=startup, userName=userName,password=password, exeName=exeName, displayName = serviceDisplayName, perfMonIni=perfMonIni,perfMonDll=perfMonDll)
  490.                 print "Service updated"
  491.             except win32service.error, (hr, fn, msg):
  492.                 print "Error changing service configuration: %s" % msg
  493.                 err = hr
  494.  
  495.         elif arg=="remove":
  496.             knownArg = 1
  497.             print "Removing service %s" % (serviceName)
  498.             try:
  499.                 RemoveService(serviceName)
  500.                 print "Service removed"
  501.             except win32service.error, (hr, fn, msg):
  502.                 print "Error removing service: %s" % msg
  503.                 err = hr
  504.         elif arg=="stop":
  505.             knownArg = 1
  506.             print "Stopping service %s" % (serviceName)
  507.             try:
  508.                 StopService(serviceName)
  509.             except win32service.error, (hr, fn, msg):
  510.                 print "Error stopping service: %s" % msg
  511.                 err = hr
  512.         if not knownArg:
  513.             err = -1
  514.             print "Unknown command - '%s'" % arg
  515.             usage()
  516.     return err
  517.  
  518. #
  519. # Useful base class to build services from.
  520. #
  521. class ServiceFramework:
  522.     # _svc_name = The service name
  523.     # _svc_display_name = The service display name
  524.     def __init__(self, args):
  525.         import servicemanager
  526.         self.ssh = servicemanager.RegisterServiceCtrlHandler(args[0], self.ServiceCtrlHandler)
  527.         self.checkPoint = 0
  528.  
  529.     def GetAcceptedControls(self):
  530.         # Setup the service controls we accept based on our attributes
  531.         accepted = 0
  532.         if hasattr(self, "SvcStop"): accepted = accepted | win32service.SERVICE_ACCEPT_STOP
  533.         if hasattr(self, "SvcPause") and hasattr(self, "SvcContinue"):
  534.             accepted = accepted | win32service.SERVICE_ACCEPT_PAUSE_CONTINUE
  535.         if hasattr(self, "SvcShutdown"): accepted = accepted | win32service.SERVICE_ACCEPT_SHUTDOWN
  536.         return accepted
  537.             
  538.     def ReportServiceStatus(self, serviceStatus, waitHint = 5000, win32ExitCode = 0, svcExitCode = 0):
  539.         if self.ssh is None: # Debugging!
  540.             return
  541.         if serviceStatus == win32service.SERVICE_START_PENDING:
  542.             accepted = 0
  543.         else:
  544.             accepted = self.GetAcceptedControls()
  545.  
  546.         if serviceStatus in [win32service.SERVICE_RUNNING,  win32service.SERVICE_STOPPED]:
  547.             checkPoint = 0
  548.         else:
  549.             self.checkPoint = self.checkPoint + 1
  550.             checkPoint = self.checkPoint
  551.  
  552.         # Now report the status to the control manager
  553.         status = (win32service.SERVICE_WIN32_OWN_PROCESS,
  554.                  serviceStatus,
  555.                  accepted, # dwControlsAccepted,
  556.                  win32ExitCode, # dwWin32ExitCode; 
  557.                  svcExitCode, # dwServiceSpecificExitCode; 
  558.                  checkPoint, # dwCheckPoint; 
  559.                  waitHint)
  560.         win32service.SetServiceStatus( self.ssh, status)
  561.               
  562.     def SvcInterrogate(self):
  563.           # Assume we are running, and everyone is happy.
  564.           self.ReportServiceStatus(win32service.SERVICE_RUNNING)
  565.  
  566.     def SvcOther(self, control):
  567.           print "Unknown control status - %d" % control
  568.  
  569.     def ServiceCtrlHandler(self, control):
  570.         if control==win32service.SERVICE_CONTROL_STOP:
  571.             self.SvcStop()
  572.         elif control==win32service.SERVICE_CONTROL_PAUSE:
  573.             self.SvcPause()
  574.         elif control==win32service.SERVICE_CONTROL_CONTINUE:
  575.             self.SvcContinue()
  576.         elif control==win32service.SERVICE_CONTROL_INTERROGATE:
  577.             self.SvcInterrogate()
  578.         elif control==win32service.SERVICE_CONTROL_SHUTDOWN:
  579.             self.SvcShutdown()
  580.         else:
  581.             self.SvcOther(control)
  582.  
  583.     def SvcRun(self):
  584.         self.ReportServiceStatus(win32service.SERVICE_RUNNING)
  585.         self.SvcDoRun()
  586.         # Once SvcDoRun terminates, the service has stopped.
  587.         # We tell the SCM the service is still stopping - the C framework
  588.         # will automatically tell the SCM it has stopped when this returns.
  589.         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  590.  
  591.  
  592.